home *** CD-ROM | disk | FTP | other *** search
Text File | 1989-04-27 | 7.3 KB | 209 lines | [TEXT/????] |
- ;;; 12/23/87 (mh) modified CHEB-ECON to return original poly if not trimmed
- ;;; $Header: chebpoly.scm,v 1.3 88/01/26 06:58:01 GMT gjs Exp $
- ;;; Chebyshev polynomial routines
-
- (if-mit
- (declare (usual-integrations = + - * /
- zero? 1+ -1+
- ;; truncate round floor ceiling
- sqrt exp log sin cos)))
-
-
- ;;; We define a function that returns a stream of Chebyshev polynomials,
- ;;; using the recurrence relation
- ;;; T[0] = 1, T[1] = x, T[n] = 2xT[n-1] - T[n-2]
-
- (define (chebyshev-polynomials)
- (define s
- (cons-stream
- '(1)
- (cons-stream
- '(0 1)
- (map-streams (lambda (p1 p2)
- (sub-polys (mul-polys '(0 2) p1) p2))
- (tail s)
- s))))
- s)
-
- ;;; The following procedure returns the Nth Chebyshev polynomial
-
- (define (cheb-poly n)
- (let ((s (chebyshev-polynomials)))
- (stream-ref s n)))
-
-
- ;;; In the following, we define a CHEB-EXP to be an expansion in
- ;;; Chebyshev polynomials. As with polynomials, the expansion is
- ;;; written as a list of coefficients (a0 a1 ... aN), and represents
- ;;; the formal series a0*T[0](x) + ... + aN*T[N](x).
-
- ;;; The following procedure returns a stream of scaled Chebyshev
- ;;; expansions: precisely, it returns the expansions corresponding
- ;;; to the sequence 1, x, 2x^2, 4x^3, ..., 2^(n-1)x^n ... Note that the
- ;;; general form doesn't cover the first term. What is generally wanted
- ;;; is the expansion corresponding to x^n; the power of 2 is thrown in
- ;;; so that the resulting expansion is exact in integer arithmetic.
-
- (define (scaled-chebyshev-expansions)
- (define (2x cheb-exp)
- (let ((t1 (cdr cheb-exp))
- (t2 (append (list 0) cheb-exp))
- (t3 (list 0 (car cheb-exp))))
- (add-polys t1 (add-polys t2 t3))))
- (define s
- (cons-stream
- '(1)
- (cons-stream
- '(0 1)
- (map-stream 2x (tail s)))))
- s)
-
-
- ;;; For convenience, we also provide the non-scaled Chebyshev expansions
-
- (define (chebyshev-expansions)
- (letrec ((s (cons-stream ; s = {1 1 2 4 8 16 ...}
- 1
- (cons-stream
- 1
- (map-stream (lambda(x) (+ x x)) (tail s)))))
- (c (scaled-chebyshev-expansions)))
- (map-streams (lambda (factor poly)
- (scale-poly (/ 1 factor) poly))
- s
- c)))
-
-
- ;;; Convert from polynomial form to Chebyshev expansion
-
- (define (poly->cheb-exp p)
- (let ((n (length p)))
- (let ((cheb (first-n-of-stream (chebyshev-expansions) n)))
- (reduce
- add-polys
- (map scale-poly p cheb)))))
-
- ;;; Convert from Chebyshev expansion to polynomial form
-
- (define (cheb-exp->poly p)
- (let ((n (length p)))
- (let ((cheb (first-n-of-stream (chebyshev-polynomials) n)))
- (reduce
- add-polys
- (map scale-poly p cheb)))))
-
- ;;; Given a Cheb-expansion and an error criterion EPS, trim the tail of
- ;;; those coefficients whose absolute sum is <= EPS.
-
- (define (trim-cheb-exp cheb eps)
- (let ((r (reverse cheb)))
- (let loop ((sum (abs (car r))) (r r))
- (if (= (length r) 1)
- (if (<= sum eps) '(0) r)
- (if (> sum eps)
- (reverse r)
- (loop (+ sum (abs (cadr r))) (cdr r)))))))
-
-
- ;;; The next procedure performs Chebyshev economization on a polynomial p
- ;;; over a specified interval [a,b]: the returned polynomial is guaranteed
- ;;; to differ from the original by no more than eps over [a, b].
-
- (define (cheb-econ p a b eps)
- (let ((q (poly-domain->canonical p a b)))
- (let ((r (poly->cheb-exp q)))
- (let ((s (trim-cheb-exp r eps)))
- (if (= (length s) (length r)) ;nothing got trimmed
- p
- (let ((t (cheb-exp->poly s)))
- (poly-domain->general t a b)))))))
-
-
- ;;; Return the root-list of the Nth Chebyshev polynomial
-
- (define (cheb-root-list n)
- (define (root i)
- (if (and (odd? n) (= i (/ (- n 1) 2)))
- 0
- (- (cos (/ (* (+ i (/ 1 2)) pi) n)))))
- (let loop ((i 0))
- (if (= i n)
- '()
- (cons (root i)
- (loop (+ i 1))))))
-
- ;;; This procedure accepts an integer n > 0 and a real x, and returns
- ;;; a list of the values T[0](x) ... T[n-1](x). If an optional third
- ;;; argument is given as the symbol 'HALF, then the first value in the
- ;;; list will have the value 0.5; otherwise it has the value 1.
-
- (define (first-n-cheb-values n x . optionals)
- (let ((first (if (and (not (null? optionals))
- (eq? (car optionals) 'HALF))
- (/ 1 2)
- 1)))
- (cond ((< n 1) '())
- ((= n 1) (list first))
- ((= n 2) (list first x))
- (else (let loop ((ans (list x first)) (a 1) (b x) (count 2))
- (if (= count n)
- (reverse ans)
- (let ((next (- (* 2 x b) a)))
- (loop (cons next ans) b next (+ count 1)))))))))
-
-
- ;;; The following procedure evaluates a cheb-expansion directly, in a
- ;;; manner analogous to Horner's method for evaluating polynomials --
- ;;; actually, it isn't as analogous as it should be, and should
- ;;; probably be replaced by Clenshaw's method which truly is like
- ;;; Horner's.
-
- (define (cheb-exp-value cheb x)
- (let ((n (length cheb)))
- (let ((vals (first-n-cheb-values n x)))
- (reduce + (map * cheb vals)))))
-
-
- ;;; This procedure generates a Chebyshev expansion to a given order N,
- ;;; for a function f specified on an interval [a,b]. The interval is
- ;;; mapped onto [-1,1] and the function approximated is g, defined on
- ;;; [-1,1] to behave the same as f on [a,b].
- ;;; Note: the returned list of coefficients is N long, and is associated
- ;;; with Chebyshev polynomials from T[0] to T[N-1].
-
- (define (generate-cheb-exp f a b n)
- (if (<= b a)
- (error "Bad interval in GENERATE-CHEB-EXP"))
- (let ((interval-map ;map [-1,1] onto [a,b]
- (let ((c (/ (+ a b) 2))
- (d (/ (- b a) 2)))
- (lambda (x) (+ c (* d x))))))
- (let ((roots (cheb-root-list n))
- (polys (first-n-of-stream (chebyshev-polynomials) n)))
- (let ((vals (map f (map interval-map roots))))
- (let loop ((coeffs '()) (i 0))
- (if (= i n)
- (reverse coeffs)
- (let ((chebf (lambda(x) (poly-value (list-ref polys i) x))))
- (let ((chebvals (map chebf roots)))
- (let ((sum (reduce + (map * vals chebvals))))
- (let ((term (if (zero? i) (/ sum n) (/ (* 2 sum) n))))
- (loop (cons term coeffs) (+ i 1))))))))))))
-
-
- ;;; This procedure accepts a function f, an interval [a,b], a number
- ;;; N of points at which to base a Chebyshev interpolation, and an
- ;;; optional precision EPS. The method is to map f onto the canonical
- ;;; interval [-1,1], generate the Chebyshev expansion based on the
- ;;; first N Chebyshev polynomials interpolating at the roots of the
- ;;; N+1st Chebyshev polynomial T[N]. If EPS has been specified, an
- ;;; economization is performed at this point; otherwise not. Finally,
- ;;; the Chebyshev expansion is reconverted to a polynomial and mapped
- ;;; back onto the original interval [a,b].
-
- (define (generate-approx-poly f a b n . optionals)
- (let ((eps (if (null? optionals) false (car optionals))))
- (let ((p (generate-cheb-exp f a b n)))
- (let ((pp (if eps (trim-cheb-exp p eps) p)))
- (poly-domain->general (cheb-exp->poly pp) a b)))))
-